/**********************************************************************\

 Copyright 2012 Diggory Blake

 This file is part of klip-engine

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

\**********************************************************************/
#pragma once

#include <math.h>
#include <algorithm>

#include "kcommon.h"
#include "kerror.h"

struct kVec2;
struct kVec3;
struct kMat3x3;
struct kColor;
struct kRect;
struct kVec2i;

struct kVec2 {
public:
	static const unsigned components = 2;

	union {
		struct {
			float x, y;
		};
		float v[2];
	};

	inline kVec2() {
		this->x = 0;
		this->y = 0;
	}
	inline explicit kVec2(float v) {
		this->x = v;
		this->y = v;
	}
	inline explicit kVec2(float* v) {
		for (int i = 0; i < 2; i++)
			this->v[i] = v[i];
	}
	inline kVec2(float x, float y) {
		this->x = x;
		this->y = y;
	}
	inline explicit kVec2(const kVec2i& v);

	friend kVec2 operator-(const kVec2& a);
	friend kVec2 operator+(const kVec2& a, const kVec2& b);
	friend kVec2 operator-(const kVec2& a, const kVec2& b);
	friend kVec2 operator*(const kVec2& a, const kVec2& b);
	friend kVec2 operator/(const kVec2& a, const kVec2& b);
	friend kVec2 operator*(const kVec2& a, float b);
	friend kVec2 operator/(const kVec2& a, float b);
	friend kVec2 operator*(float a, const kVec2& b);
	friend kVec2& operator+=(kVec2& a, const kVec2& b);
	friend kVec2& operator-=(kVec2& a, const kVec2& b);
	friend kVec2& operator*=(kVec2& a, const kVec2& b);
	friend kVec2& operator/=(kVec2& a, const kVec2& b);
	friend kVec2& operator*=(kVec2& a, float b);
	friend kVec2& operator/=(kVec2& a, float b);
	friend float dot(const kVec2& a, const kVec2& b);
	friend kVec2 cross(const kVec2& a);
	friend float cross(const kVec2& a, const kVec2& b);
	friend kVec2 transform(const kMat3x3& a, const kVec2& b);
	friend kVec2 transform(const kVec2& a, const kMat3x3& b);
	friend kVec2 transformNormal(const kMat3x3& a, const kVec2& b);
	friend kVec2 transformNormal(const kVec2& a, const kMat3x3& b);
	friend float lengthSq(const kVec2& a);
	friend float length(const kVec2& a);
	friend kVec2 normalize(const kVec2& a);

	friend kVec2 operator+(const kVec2i& a, const kVec2& b);
	friend kVec2 operator-(const kVec2i& a, const kVec2& b);
	friend kVec2 operator*(const kVec2i& a, const kVec2& b);
	friend kVec2 operator/(const kVec2i& a, const kVec2& b);
	friend kVec2 operator+(const kVec2& a, const kVec2i& b);
	friend kVec2 operator-(const kVec2& a, const kVec2i& b);
	friend kVec2 operator*(const kVec2& a, const kVec2i& b);
	friend kVec2 operator/(const kVec2& a, const kVec2i& b);
};

struct kVec3 {
public:
	static const unsigned components = 3;

	union {
		struct {
			float x, y, z;
		};
		float v[3];
	};

	inline kVec3() {
		this->x = 0;
		this->y = 0;
		this->z = 0;
	}
	inline explicit kVec3(float v) {
		this->x = v;
		this->y = v;
		this->z = v;
	}
	inline explicit kVec3(float* v) {
		for (int i = 0; i < 3; i++)
			this->v[i] = v[i];
	}
	inline explicit kVec3(const kVec2& xy) {
		this->x = xy.x;
		this->y = xy.y;
		this->z = 0;
	}
	inline kVec3(float x, float y, float z) {
		this->x = x;
		this->y = y;
		this->z = z;
	}
	inline kVec3(const kVec2& xy, float z) {
		this->x = xy.x;
		this->y = xy.y;
		this->z = z;
	}
	inline kVec3(float x, const kVec2& yz) {
		this->x = x;
		this->y = yz.x;
		this->z = yz.y;
	}

	friend kVec3 operator-(const kVec3& a);
	friend kVec3 operator+(const kVec3& a, const kVec3& b);
	friend kVec3 operator-(const kVec3& a, const kVec3& b);
	friend kVec3 operator*(const kVec3& a, const kVec3& b);
	friend kVec3 operator/(const kVec3& a, const kVec3& b);
	friend kVec3 operator*(const kVec3& a, float b);
	friend kVec3 operator/(const kVec3& a, float b);
	friend kVec3 operator*(float a, const kVec3& b);
	friend kVec3& operator+=(kVec3& a, const kVec3& b);
	friend kVec3& operator-=(kVec3& a, const kVec3& b);
	friend kVec3& operator*=(kVec3& a, const kVec3& b);
	friend kVec3& operator/=(kVec3& a, const kVec3& b);
	friend kVec3& operator*=(kVec3& a, float b);
	friend kVec3& operator/=(kVec3& a, float b);
	friend float dot(const kVec3& a, const kVec3& b);
	friend kVec3 cross(const kVec3& a, const kVec3& b);
	friend kVec3 transform(const kMat3x3& a, const kVec3& b);
	friend kVec3 transform(const kVec3& a, const kMat3x3& b);
	friend float lengthSq(const kVec3& a);
	friend float length(const kVec3& a);
	friend kVec3 normalize(const kVec3& a);
};

struct kMat3x3 {
public:
	static const unsigned components = 9;

	union {
		struct {
			float m00, m01, m02;
			float m10, m11, m12;
			float m20, m21, m22;
		};
		float m[3][3];
		float v[9];
	};

	inline kMat3x3() {
		m00 = 1.0f; m01 = 0.0f; m02 = 0.0f;
		m10 = 0.0f; m11 = 1.0f; m12 = 0.0f;
		m20 = 0.0f; m21 = 0.0f; m22 = 1.0f;
	}
	inline explicit kMat3x3(float* v) {
		for (int i = 0; i < 9; i++)
			this->v[i] = v[i];
	}
	inline kMat3x3(
		float m00, float m01, float m02,
		float m10, float m11, float m12,
		float m20, float m21, float m22) {
		this->m00 = m00; this->m01 = m01; this->m02 = m02;
		this->m10 = m10; this->m11 = m11; this->m12 = m12;
		this->m20 = m20; this->m21 = m21; this->m22 = m22;
	}

	friend kMat3x3 operator*(const kMat3x3& a, const kMat3x3& b);
	friend float det(const kMat3x3& a);
	friend kMat3x3 transpose(const kMat3x3& a);
	friend kMat3x3 inverse(const kMat3x3& a);
	friend kMat3x3 adjoint(const kMat3x3& a);

	static inline kMat3x3 scale(float scale) {
		return kMat3x3(scale, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 1.0f);
	}
	static inline kMat3x3 scale(const kVec2& scale) {
		return kMat3x3(scale.x, 0.0f, 0.0f, 0.0f, scale.y, 0.0f, 0.0f, 0.0f, 1.0f);
	}
	static inline kMat3x3 translate(const kVec2& offset) {
		return kMat3x3(1.0f, 0.0f, offset.x, 0.0f, 1.0f, offset.y, 0.0f, 0.0f, 1.0f);
	}
	static inline kMat3x3 rotate(float angle) {
		float ca = cos(angle), sa = sin(angle);
		return kMat3x3(ca, -sa, 0.0f, sa, ca, 0.0f, 0.0f, 0.0f, 1.0f);
	}
	static inline kMat3x3 shear(const kVec2& shear) {
		return kMat3x3(1.0f, shear.x, 0.0f, shear.y, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
	}
};

struct kColor {
public:
	static const unsigned components = 4;

	union {
		struct {
			float a, r, g, b;
		};
		struct {
			float alpha, red, green, blue;
		};
		float v[4];
	};

	inline kColor() {
		this->a = 0.0f;
		this->r = 0.0f;
		this->g = 0.0f;
		this->b = 0.0f;
	}
	inline explicit kColor(unsigned argb) {
		this->a = (argb >> 24)/255.0f;
		this->r = ((argb >> 16) & 0xFF)/255.0f;
		this->g = ((argb >> 8) & 0xFF)/255.0f;
		this->b = (argb & 0xFF)/255.0f;
	}
	inline explicit kColor(float* v) {
		for (int i = 0; i < 4; i++)
			this->v[i] = v[i];
	}
	inline kColor(float r, float g, float b) {
		this->a = 1.0f;
		this->r = r;
		this->g = g;
		this->b = b;
	}
	inline kColor(float a, float r, float g, float b) {
		this->a = a;
		this->r = r;
		this->g = g;
		this->b = b;
	}

	friend kColor operator*(const kColor& a, const kColor& b);
	friend kColor operator*(float a, const kColor& b);
	friend kColor operator*(const kColor& a, float b);
	friend kColor operator+(const kColor& a, const kColor& b);
	friend kColor operator-(const kColor& a, const kColor& b);
	friend kColor operator/(const kColor& a, const kColor& b);
	friend kColor operator/(const kColor& a, float b);
	
	inline unsigned toArgb() const {
		unsigned a = 0xFF & (unsigned)(this->a*255.0f+0.5f);
		unsigned r = 0xFF & (unsigned)(this->r*255.0f+0.5f);
		unsigned g = 0xFF & (unsigned)(this->g*255.0f+0.5f);
		unsigned b = 0xFF & (unsigned)(this->b*255.0f+0.5f);

		return (a << 24)|(r << 16)|(g << 8)|b;
	}
};

struct kVec2i {
public:
	static const unsigned components = 2;

	union {
		struct {
			int x, y;
		};
		int v[2];
	};

	inline kVec2i() {
		this->x = 0;
		this->y = 0;
	}
	inline explicit kVec2i(int v) {
		this->x = v;
		this->y = v;
	}
	inline explicit kVec2i(int* v) {
		for (int i = 0; i < 2; i++)
			this->v[i] = v[i];
	}
	inline kVec2i(int x, int y) {
		this->x = x;
		this->y = y;
	}
	inline explicit kVec2i(const kVec2& v) {
		x = (int)v.x;
		y = (int)v.y;
	}

	friend kVec2i operator-(const kVec2i& a);
	friend kVec2i operator+(const kVec2i& a, const kVec2i& b);
	friend kVec2i operator-(const kVec2i& a, const kVec2i& b);
	friend kVec2i operator*(const kVec2i& a, const kVec2i& b);
	friend kVec2i operator/(const kVec2i& a, const kVec2i& b);
	friend kVec2i operator*(const kVec2i& a, int b);
	friend kVec2i operator/(const kVec2i& a, int b);
	friend kVec2i operator*(int a, const kVec2& b);
	friend kVec2i& operator+=(kVec2i& a, const kVec2i& b);
	friend kVec2i& operator-=(kVec2i& a, const kVec2i& b);
	friend kVec2i& operator*=(kVec2i& a, const kVec2i& b);
	friend kVec2i& operator/=(kVec2i& a, const kVec2i& b);
	friend kVec2i& operator*=(kVec2i& a, int b);
	friend kVec2i& operator/=(kVec2i& a, int b);
	friend int dot(const kVec2i& a, const kVec2i& b);
	friend kVec2i cross(const kVec2i& a);
	friend int cross(const kVec2i& a, const kVec2i& b);
	friend int lengthSq(const kVec2i& a);
	friend float length(const kVec2i& a);
	friend bool operator==(const kVec2i& a, const kVec2i& b);
	friend bool operator!=(const kVec2i& a, const kVec2i& b);

	friend kVec2 operator+(const kVec2i& a, const kVec2& b);
	friend kVec2 operator-(const kVec2i& a, const kVec2& b);
	friend kVec2 operator*(const kVec2i& a, const kVec2& b);
	friend kVec2 operator/(const kVec2i& a, const kVec2& b);
	friend kVec2 operator+(const kVec2& a, const kVec2i& b);
	friend kVec2 operator-(const kVec2& a, const kVec2i& b);
	friend kVec2 operator*(const kVec2& a, const kVec2i& b);
	friend kVec2 operator/(const kVec2& a, const kVec2i& b);
	friend kVec2 operator*(const kVec2i& a, float b);
	friend kVec2 operator/(const kVec2i& a, float b);
	friend kVec2 operator*(float a, const kVec2i& b);
};

struct kRect {
	int left, top, width, height;

	inline kRect() {
		this->left = 0;
		this->top = 0;
		this->width = 0;
		this->height = 0;
	}
	inline kRect(int left, int top, int width, int height) {
		this->left = left;
		this->top = top;
		this->width = width;
		this->height = height;
	}
	inline kRect(const kVec2i& pos, const kVec2i& size) {
		this->left = pos.x;
		this->top = pos.y;
		this->width = size.x;
		this->height = size.y;
	}

	inline kRect offset(int x, int y) const {
		return kRect(left+x, top+y, width, height);
	}
	inline kRect intersect(const kRect& other) const {
		int x1 = (std::max)(left, other.left);
		int y1 = (std::max)(top, other.top);
		int x2 = (std::min)(left+width, other.left+other.width);
		int y2 = (std::min)(top+height, other.top+other.height);
		return kRect(x1, y1, x2 - x1, y2 - y1);
	}
	inline kRect add(const kRect& other) const {
		int x1 = (std::min)(left, other.left);
		int y1 = (std::min)(top, other.top);
		int x2 = (std::max)(left+width, other.left+other.width);
		int y2 = (std::max)(top+height, other.top+other.height);
		return kRect(x1, y1, x2 - x1, y2 - y1);
	}
	inline kVec2i getPos() const {
		return kVec2i(left, top);
	}
	inline kVec2i getSize() const {
		return kVec2i(width, height);
	}
};

struct kAABB {
	float left, top, right, bottom;

	inline kAABB() {
		this->left = 0.0f;
		this->top = 0.0f;
		this->right = 0.0f;
		this->bottom = 0.0f;
	}
	inline kAABB(float left, float top, float right, float bottom) {
		this->left = left;
		this->top = top;
		this->right = right;
		this->bottom = bottom;
	}
	template<typename T> inline kAABB(T begin, T end) {
		auto i = begin;
		this->left = i->x;
		this->top = i->y;
		this->right = i->x;
		this->bottom = i->y;
		for (i++; i != end; i++) {
			this->left = std::min(this->left, i->x);
			this->top = std::min(this->top, i->y);
			this->right = std::max(this->right, i->x);
			this->bottom = std::max(this->bottom, i->y);
		}
	}

	inline bool empty() const {
		return (right <= left) || (bottom <= top);
	}
	inline kAABB offset(float x, float y) const {
		return kAABB(left+x, top+y, right+x, bottom+y);
	}
	inline kAABB intersect(const kAABB& other) const {
		return kAABB(
			(std::max)(left, other.left), (std::max)(top, other.top),
			(std::min)(right, other.right), (std::min)(bottom, other.bottom)
			);
	}
	inline kAABB add(const kAABB& other) const {
		if (empty())
			return other;
		else if (other.empty())
			return *this;
		else
			return kAABB(
				(std::min)(left, other.left), (std::min)(top, other.top),
				(std::max)(right, other.right), (std::max)(bottom, other.bottom)
				);
	}
	inline bool intersects(const kAABB& other) const {
		return !intersect(other).empty();
	}
	inline float area() const {
		if (empty())
			return 0.0f;
		else
			return (right-left)*(bottom-top);
	}
	inline kVec2 getPos() const {
		return kVec2(left, top);
	}
	inline kVec2 getSize() const {
		return kVec2(right-left, bottom-top);
	}
	inline bool contains(const kVec2& other) const {
		return (left <= other.x) && (right > other.x) && (top <= other.y) && (bottom > other.y);
	}
};

inline kVec2 operator-(const kVec2& a) {
	return kVec2(-a.x, -a.y);
}
inline kVec2 operator+(const kVec2& a, const kVec2& b) {
	return kVec2(a.x + b.x, a.y + b.y);
}
inline kVec2 operator-(const kVec2& a, const kVec2& b) {
	return kVec2(a.x - b.x, a.y - b.y);
}
inline kVec2 operator*(const kVec2& a, const kVec2& b) {
	return kVec2(a.x * b.x, a.y * b.y);
}
inline kVec2 operator/(const kVec2& a, const kVec2& b) {
	return kVec2(a.x / b.x, a.y / b.y);
}
inline kVec2 operator*(const kVec2& a, float b) {
	return kVec2(a.x * b, a.y * b);
}
inline kVec2 operator/(const kVec2& a, float b) {
	b = 1.0f/b;
	return kVec2(a.x * b, a.y * b);
}
inline kVec2 operator*(float a, const kVec2& b) {
	return kVec2(a * b.x, a * b.y);
}
inline kVec2& operator+=(kVec2& a, const kVec2& b) {
	a.x += b.x;
	a.y += b.y;
	return a;
}
inline kVec2& operator-=(kVec2& a, const kVec2& b) {
	a.x -= b.x;
	a.y -= b.y;
	return a;
}
inline kVec2& operator*=(kVec2& a, const kVec2& b) {
	a.x *= b.x;
	a.y *= b.y;
	return a;
}
inline kVec2& operator/=(kVec2& a, const kVec2& b) {
	a.x /= b.x;
	a.y /= b.y;
	return a;
}
inline kVec2& operator*=(kVec2& a, float b) {
	a.x *= b;
	a.y *= b;
	return a;
}
inline kVec2& operator/=(kVec2& a, float b) {
	b = 1.0f/b;
	a.x *= b;
	a.y *= b;
	return a;
}
inline float dot(const kVec2& a, const kVec2& b) {
	return a.x*b.x + a.y*b.y;
}
inline kVec2 cross(const kVec2& a) {
	return kVec2(a.y, -a.x);
}
inline float lengthSq(const kVec2& a) {
	return a.x*a.x + a.y*a.y;
}
inline float length(const kVec2& a) {
	return sqrt(a.x*a.x + a.y*a.y);
}
inline float cross(const kVec2& a, const kVec2& b) {
	return a.x*b.y - a.y*b.x;
}
inline kVec2 normalize(const kVec2& a) {
	return a/length(a);
}
inline kMat3x3 operator*(const kMat3x3& a, const kMat3x3& b) {
	return kMat3x3(
		a.m00*b.m00 + a.m01*b.m10 + a.m02*b.m20,
		a.m00*b.m01 + a.m01*b.m11 + a.m02*b.m21,
		a.m00*b.m02 + a.m01*b.m12 + a.m02*b.m22,
		a.m10*b.m00 + a.m11*b.m10 + a.m12*b.m20,
		a.m10*b.m01 + a.m11*b.m11 + a.m12*b.m21,
		a.m10*b.m02 + a.m11*b.m12 + a.m12*b.m22,
		a.m20*b.m00 + a.m21*b.m10 + a.m22*b.m20,
		a.m20*b.m01 + a.m21*b.m11 + a.m22*b.m21,
		a.m20*b.m02 + a.m21*b.m12 + a.m22*b.m22
		);
}
inline kVec2 transform(const kMat3x3& a, const kVec2& b) {
	float invz = 1.0f/(a.m20*b.x + a.m21*b.y + a.m22);
	return kVec2(
		(a.m00*b.x + a.m01*b.y + a.m02)*invz,
		(a.m10*b.x + a.m11*b.y + a.m12)*invz
		);
}
inline kVec2 transform(const kVec2& a, const kMat3x3& b) {
	float invz = 1.0f/(b.m20*a.x + b.m21*a.y + b.m22);
	return kVec2(
		(b.m00*a.x + b.m01*a.y + b.m02)*invz,
		(b.m10*a.x + b.m11*a.y + b.m12)*invz
		);
}
inline kVec2 transformNormal(const kMat3x3& a, const kVec2& b) {
	return kVec2(
		a.m00*b.x + a.m01*b.y,
		a.m10*b.x + a.m11*b.y
		);
}
inline kVec2 transformNormal(const kVec2& a, const kMat3x3& b) {
	return kVec2(
		b.m00*a.x + b.m01*a.y,
		b.m10*a.x + b.m11*a.y
		);
}
inline kVec2::kVec2(const kVec2i& v) {
	x = (float)v.x;
	y = (float)v.y;
}

inline kVec3 operator-(const kVec3& a) {
	return kVec3(-a.x, -a.y, -a.z);
}
inline kVec3 operator+(const kVec3& a, const kVec3& b) {
	return kVec3(a.x + b.x, a.y + b.y, a.z + b.z);
}
inline kVec3 operator-(const kVec3& a, const kVec3& b) {
	return kVec3(a.x - b.x, a.y - b.y, a.z - b.z);
}
inline kVec3 operator*(const kVec3& a, const kVec3& b) {
	return kVec3(a.x * b.x, a.y * b.y, a.z * b.z);
}
inline kVec3 operator/(const kVec3& a, const kVec3& b) {
	return kVec3(a.x / b.x, a.y / b.y, a.z / b.z);
}
inline kVec3 operator*(const kVec3& a, float b) {
	return kVec3(a.x * b, a.y * b, a.z * b);
}
inline kVec3 operator/(const kVec3& a, float b) {
	b = 1.0f/b;
	return kVec3(a.x * b, a.y * b, a.z * b);
}
inline kVec3 operator*(float a, const kVec3& b) {
	return kVec3(a * b.x, a * b.y, a * b.z);
}
inline kVec3& operator+=(kVec3& a, const kVec3& b) {
	a.x += b.x;
	a.y += b.y;
	a.z += b.z;
	return a;
}
inline kVec3& operator-=(kVec3& a, const kVec3& b) {
	a.x -= b.x;
	a.y -= b.y;
	a.z -= b.z;
	return a;
}
inline kVec3& operator*=(kVec3& a, const kVec3& b) {
	a.x *= b.x;
	a.y *= b.y;
	a.z *= b.z;
	return a;
}
inline kVec3& operator/=(kVec3& a, const kVec3& b) {
	a.x /= b.x;
	a.y /= b.y;
	a.z /= b.z;
	return a;
}
inline kVec3& operator*=(kVec3& a, float b) {
	a.x *= b;
	a.y *= b;
	a.z *= b;
	return a;
}
inline kVec3& operator/=(kVec3& a, float b) {
	b = 1.0f/b;
	a.x *= b;
	a.y *= b;
	a.z *= b;
	return a;
}
inline float dot(const kVec3& a, const kVec3& b) {
	return a.x*b.x + a.y*b.y + a.z*b.z;
}
inline float lengthSq(const kVec3& a) {
	return a.x*a.x + a.y*a.y + a.z*a.z;
}
inline float length(const kVec3& a) {
	return sqrt(a.x*a.x + a.y*a.y + a.z*a.z);
}
inline kVec3 cross(const kVec3& a, const kVec3& b) {
	return kVec3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
}
inline kVec3 normalize(const kVec3& a) {
	return a/length(a);
}
inline kVec3 transform(const kMat3x3& a, const kVec3& b) {
	return kVec3(
		(a.m00*b.x + a.m01*b.y + a.m02*b.z),
		(a.m10*b.x + a.m11*b.y + a.m12*b.z),
		(a.m20*b.x + a.m21*b.y + a.m22*b.z)
		);
}
inline kVec3 transform(const kVec3& a, const kMat3x3& b) {
	return kVec3(
		(b.m00*a.x + b.m01*a.y + b.m02*a.z),
		(b.m10*a.x + b.m11*a.y + b.m12*a.z),
		(b.m20*a.x + b.m21*a.y + b.m22*a.z)
		);
}

inline float det(const kMat3x3& a) {
	return a.m00*a.m11*a.m22 + a.m10*a.m21*a.m02 + a.m20*a.m01*a.m12
		 - a.m02*a.m11*a.m20 - a.m12*a.m21*a.m00 - a.m22*a.m01*a.m10;
}
inline kMat3x3 transpose(const kMat3x3& a) {
	return kMat3x3(
		a.m00, a.m10, a.m20,
		a.m01, a.m11, a.m21,
		a.m02, a.m12, a.m22
		);
}
inline kMat3x3 inverse(const kMat3x3& a) {
	float invd = 1.0f/det(a);
	return kMat3x3(
		(a.m11*a.m22 - a.m12*a.m21)*invd, (a.m20*a.m12 - a.m10*a.m22)*invd, (a.m10*a.m21 - a.m20*a.m11)*invd,
		(a.m21*a.m02 - a.m01*a.m22)*invd, (a.m00*a.m22 - a.m20*a.m02)*invd, (a.m20*a.m01 - a.m00*a.m21)*invd,
		(a.m01*a.m12 - a.m11*a.m02)*invd, (a.m10*a.m02 - a.m00*a.m12)*invd, (a.m00*a.m11 - a.m10*a.m01)*invd
		);
}
inline kMat3x3 adjoint(const kMat3x3& a) {
	return kMat3x3(
		(a.m11*a.m22 - a.m12*a.m21), (a.m20*a.m12 - a.m10*a.m22), (a.m10*a.m21 - a.m20*a.m11),
		(a.m21*a.m02 - a.m01*a.m22), (a.m00*a.m22 - a.m20*a.m02), (a.m20*a.m01 - a.m00*a.m21),
		(a.m01*a.m12 - a.m11*a.m02), (a.m10*a.m02 - a.m00*a.m12), (a.m00*a.m11 - a.m10*a.m01)
		);
}
inline void decompose(const kMat3x3& a, kVec2* position, kVec2* scale, float* angle) {
	float invz = 1.0f/a.m22;
	if (position) {
		position->x = a.m02*invz;
		position->y = a.m12*invz;
	}

	if (abs(a.m00 + a.m11) + abs(a.m10 - a.m01) >= abs(a.m00 - a.m11) + abs(a.m10 + a.m01)) {
		if (angle) {
			*angle = atan2(a.m10 - a.m01, a.m00 + a.m11);
		}

		if (scale) {
			scale->x = sqrt(a.m00*a.m00 + a.m10*a.m10)*invz;
			scale->y = sqrt(a.m01*a.m01 + a.m11*a.m11)*invz;
		}
	} else {
		if (angle) {
			*angle = atan2(a.m10 + a.m01, a.m00 - a.m11);
		}

		if (scale) {
			scale->x = sqrt(a.m00*a.m00 + a.m10*a.m10)*invz;
			scale->y = -sqrt(a.m01*a.m01 + a.m11*a.m11)*invz;
		}
	}
}
inline void compose(kMat3x3* a, const kVec2& position, const kVec2& scale, float angle) {
	if (a) {
		float ca = cos(angle);
		float sa = sin(angle);
		a->m00 = ca*scale.x;	a->m01 = -sa*scale.y;	a->m02 = position.x;
		a->m10 = sa*scale.x;	a->m11 =  ca*scale.y;	a->m12 = position.y;
		a->m20 = 0.0f;			a->m21 = 0.0f;			a->m22 = 1.0f;
	}
}
inline kMat3x3 translation(const kVec2& offset) {
	return kMat3x3(
		1.0f, 0.0f, offset.x,
		0.0f, 1.0f, offset.y,
		0.0f, 0.0f, 1.0f
		);
}
inline kMat3x3 rotation(float angle) {
	float ca = cos(angle);
	float sa = sin(angle);
	return kMat3x3(
		ca, -sa, 0.0f,
		sa, ca, 0.0f,
		0.0f, 0.0f, 1.0f
		);
}
inline kMat3x3 scale(const kVec2& scale) {
	return kMat3x3(
		scale.x, 0.0f, 0.0f,
		0.0f, scale.y, 0.0f,
		0.0f, 0.0f, 1.0f
		);
}
template<typename T> inline T clamp(const T& a, float minValue = 0.0f, float maxValue = 1.0f) {
	T result;
	for (unsigned i = 0; i < T::components; i++) {
		if (a.v[i] > maxValue)
			result.v[i] = maxValue;
		else if (a.v[i] < minValue)
			result.v[i] = minValue;
		else
			result.v[i] = a.v[i];
	}

	return result;
}
inline float clamp(float a, float minValue = 0.0f, float maxValue = 1.0f) {
	if (a > maxValue)
		return maxValue;
	else if (a < minValue)
		return minValue;
	else
		return a;
}
inline kColor operator*(const kColor& a, const kColor& b) {
	return kColor(a.a*b.a, a.r*b.r, a.g*b.g, a.b*b.b);
}
inline kColor operator*(float a, const kColor& b) {
	return kColor(a*b.a, a*b.r, a*b.g, a*b.b);
}
inline kColor operator*(const kColor& a, float b) {
	return kColor(a.a*b, a.r*b, a.g*b, a.b*b);
}
inline kColor operator+(const kColor& a, const kColor& b) {
	return kColor(a.a+b.a, a.r+b.r, a.g+b.g, a.b+b.b);
}
inline kColor operator-(const kColor& a, const kColor& b) {
	return kColor(a.a-b.a, a.r-b.r, a.g-b.g, a.b-b.b);
}
inline kColor operator/(const kColor& a, const kColor& b) {
	return kColor(a.a/b.a, a.r/b.r, a.g/b.g, a.b/b.b);
}
inline kColor operator/(const kColor& a, float b) {
	b = 1.0f/b;
	return kColor(a.a*b, a.r*b, a.g*b, a.b*b);
}

inline kVec2i operator-(const kVec2i& a) {
	return kVec2i(-a.x, -a.y);
}
inline kVec2i operator+(const kVec2i& a, const kVec2i& b) {
	return kVec2i(a.x + b.x, a.y + b.y);
}
inline kVec2i operator-(const kVec2i& a, const kVec2i& b) {
	return kVec2i(a.x - b.x, a.y - b.y);
}
inline kVec2i operator*(const kVec2i& a, const kVec2i& b) {
	return kVec2i(a.x * b.x, a.y * b.y);
}
inline kVec2i operator/(const kVec2i& a, const kVec2i& b) {
	return kVec2i(a.x / b.x, a.y / b.y);
}
inline kVec2i operator*(const kVec2i& a, int b) {
	return kVec2i(a.x * b, a.y * b);
}
inline kVec2i operator/(const kVec2i& a, int b) {
	return kVec2i(a.x / b, a.y / b);
}
inline kVec2i operator*(int a, const kVec2i& b) {
	return kVec2i(a * b.x, a * b.y);
}
inline kVec2i& operator+=(kVec2i& a, const kVec2i& b) {
	a.x += b.x;
	a.y += b.y;
	return a;
}
inline kVec2i& operator-=(kVec2i& a, const kVec2i& b) {
	a.x -= b.x;
	a.y -= b.y;
	return a;
}
inline kVec2i& operator*=(kVec2i& a, const kVec2i& b) {
	a.x *= b.x;
	a.y *= b.y;
	return a;
}
inline kVec2i& operator/=(kVec2i& a, const kVec2i& b) {
	a.x /= b.x;
	a.y /= b.y;
	return a;
}
inline kVec2i& operator*=(kVec2i& a, int b) {
	a.x *= b;
	a.y *= b;
	return a;
}
inline kVec2i& operator/=(kVec2i& a, int b) {
	a.x /= b;
	a.y /= b;
	return a;
}
inline int dot(const kVec2i& a, const kVec2i& b) {
	return a.x*b.x + a.y*b.y;
}
inline kVec2i cross(const kVec2i& a) {
	return kVec2i(a.y, -a.x);
}
inline int lengthSq(const kVec2i& a) {
	return a.x*a.x + a.y*a.y;
}
inline float length(const kVec2i& a) {
	return sqrt((float)(a.x*a.x + a.y*a.y));
}
inline int cross(const kVec2i& a, const kVec2i& b) {
	return a.x*b.y - a.y*b.x;
}
inline bool operator==(const kVec2i& a, const kVec2i& b) {
	return (a.x == b.x) && (a.y == b.y);
}
inline bool operator!=(const kVec2i& a, const kVec2i& b) {
	return (a.x != b.x) || (a.y != b.y);
}

inline kVec2 operator+(const kVec2i& a, const kVec2& b) {
	return kVec2(a.x + b.x, a.y + b.y);
}
inline kVec2 operator-(const kVec2i& a, const kVec2& b) {
	return kVec2(a.x - b.x, a.y - b.y);
}
inline kVec2 operator*(const kVec2i& a, const kVec2& b) {
	return kVec2(a.x * b.x, a.y * b.y);
}
inline kVec2 operator/(const kVec2i& a, const kVec2& b) {
	return kVec2(a.x / b.x, a.y / b.y);
}
inline kVec2 operator+(const kVec2& a, const kVec2i& b) {
	return kVec2(a.x + b.x, a.y + b.y);
}
inline kVec2 operator-(const kVec2& a, const kVec2i& b) {
	return kVec2(a.x - b.x, a.y - b.y);
}
inline kVec2 operator*(const kVec2& a, const kVec2i& b) {
	return kVec2(a.x * b.x, a.y * b.y);
}
inline kVec2 operator/(const kVec2& a, const kVec2i& b) {
	return kVec2(a.x / b.x, a.y / b.y);
}
inline kVec2 operator*(const kVec2i& a, float b) {
	return kVec2(a.x*b, a.y*b);
}
inline kVec2 operator/(const kVec2i& a, float b) {
	b = 1.0f/b;
	return kVec2(a.x*b, a.y*b);
}
inline kVec2 operator*(float a, const kVec2i& b) {
	return kVec2(a*b.x, a*b.y);
}

inline std::tostream& operator<<(std::tostream& a, const kVec2& b) {
  return a << b.x << _T(", ") << b.y;
}
inline std::tostream& operator<<(std::tostream& a, const kVec3& b) {
  return a << b.x << _T(", ") << b.y << _T(", ") << b.z;
}
inline std::tostream& operator<<(std::tostream& a, const kVec2i& b) {
  return a << b.x << _T(", ") << b.y;
}
inline std::tistream& operator>>(std::tistream& a, kVec2& b)
{
	tchar c;
	a >> b.x;
	do {
		a >> c;
	} while (c == _T(' '));
	if (c != _T(','))
		throw kError(_T("Invalid format!"));
	a >> b.y;

	return a;
}
inline std::tistream& operator>>(std::tistream& a, kVec3& b)
{
	tchar c;
	a >> b.x;
	do {
		a >> c;
	} while (c == _T(' '));
	if (c != _T(','))
		throw kError(_T("Invalid format!"));
	a >> b.y;
	do {
		a >> c;
	} while (c == _T(' '));
	if (c != _T(','))
		throw kError(_T("Invalid format!"));
	a >> b.z;

	return a;
}
inline std::tistream& operator>>(std::tistream& a, kVec2i& b)
{
	tchar c;
	a >> b.x;
	do {
		a >> c;
	} while (c == _T(' '));
	if (c != _T(','))
		throw kError(_T("Invalid format!"));
	a >> b.y;

	return a;
}
